#pragma once

#include "Subject.h"

class TriggerBase
{
public:
	virtual ~TriggerBase()
	{
	}
};

template <class T1, class T2>
class Trigger : public IObserver<T1>, public TriggerBase
{
public:
	Trigger(Subject<T1>* subject, T2* parent)
	{
		if (m_subject)
			m_subject->addObserver(this);
	}
	~Trigger()
	{
		if (m_subject)
			m_subject->removeObserver(this);
	}
	void Notify(const T1 &t, Subject<T1> *o)
	{
		m_parent->Notify( t, o );
	}
	void NotifyOfDeath( Subject<T1> *o)
	{
		m_subject = 0;
	}
private:
	Subject<T1>* m_subject;
	T2* m_parent;
};

template<class T1>
class ValueTrigger : public IObserver<T1>, public TriggerBase
{
	Subject<T1>* m_subject;
	T1 m_object;
public:
	ValueTrigger(Subject<T1> *subject) : m_subject(subject)
	{
		if (m_subject)
		{
			m_subject->addObserver(this);
			m_object = m_subject->getObject();
		}
	}
	~ValueTrigger()
	{
		if (m_subject)
			m_subject->removeObserver(this); 
	}
	void Notify(const T1 &t, Subject<T1> *o)
	{
		m_object = t;
	}
	void NotifyOfDeath( Subject<T1> *o)
	{
		m_subject = 0;
	}
	T1& getObject()
	{
		return m_object;
	}
	T1& operator= (const T1& o)
	{
		m_object = o;
		if (m_subject)
			*m_subject = o;
		return m_object;
	}
};


template<class T1>
class DoubleValueTrigger : public IObserver<T1>, public TriggerBase
{
	Subject<T1>* m_subject1;
	Subject<T1>* m_subject2;
	T1 m_object;
public:
	DoubleValueTrigger(Subject<T1> *subject1, Subject<T1> *subject2) : m_subject1(subject1), m_subject2(subject2)
	{
		if (m_subject1)
		{
			m_subject1->addObserver(this);
		}
		if (m_subject2)
		{
			m_subject2->addObserver(this);
		}
	}
	~DoubleValueTrigger()
	{
		if (m_subject1)
			m_subject1->removeObserver(this); 
		if (m_subject2)
			m_subject2->removeObserver(this); 
	}
	void Notify(const T1 &t, Subject<T1> *o)
	{
		static Subject<T1>* i = 0;

		if (o == i)		// i has been set as has m_object
		{
			i = 0;
			return;
		}

		m_object = t;

		if (m_subject1 && m_subject1 == o)
		{
			i = m_subject2;
			*m_subject2 = t;
		}
		else if (m_subject2 && m_subject2 == o)
		{
			i = m_subject1;
			*m_subject1 = t;
		}
	}
	void NotifyOfDeath( Subject<T1> *o )
	{
		if (m_subject1 && m_subject1 == o)
			m_subject1 = 0;
		else if (m_subject2 && m_subject2 == o)
			m_subject2 = 0;
	}
	T1& getObject()
	{
		return m_object;
	}
	T1& operator= (const T1& o)
	{
		m_object = o;
		if (m_subject1)
			*m_subject1 = o;
		if (m_subject2)
			*m_subject2 = o;
		return m_object;
	}
};